#ifndef __M_BINDING_H__
#define  __M_BINDING_H__
#include "../mqcommon/logger.hpp"
#include "../mqcommon/sqliter.hpp"
#include "../mqcommon/spliter.hpp"
#include "../mqcommon/filer.hpp"
#include "../mqcommon/message.pb.h"

#include <iostream>
#include <unordered_map>
#include <string>
#include <mutex>
#include <memory>
#include <sstream>


// 绑定信息---一个交换机关联了哪些队列的描述

/*
    1.绑定信息为 一条信息关联到一个队列的一种 约定
    2.一个交换机会管理多个队列，同时一个队列会存在一个绑定信息
    3.所以对于一个绑定信息结构体，天然的就是需要有一个对应的队列，还有队列属于的交换机，最后才是这个约定
*/

namespace zhong
{
    struct Binding
    {
        using ptr = std::shared_ptr<Binding>;
        std::string _exchange_name;
        std::string _queue_name;
        std::string _binding_key;

        Binding() {}
        Binding(const std::string &exchange_name, const std::string &queue_name, const std::string &binding_key)
            : _exchange_name(exchange_name), _queue_name(queue_name), _binding_key(binding_key) {}
    };
    // 每个队列一一对应的绑定规则 , k-v：队列-规则
    using QueueBindingMap = std::unordered_map<std::string, Binding::ptr>;
    // 每个交换机绑定的队列的哈希表，内存储多个队列的消息绑定规则
    using BindingMap = std::unordered_map<std::string, QueueBindingMap>;

    class BindingMapper
    {
    public:
        BindingMapper(const std::string &data_base_file) : _sqliter(data_base_file)
        {
            std::string path = Filer::parentDirectory(data_base_file);
            Filer::createDirectory(path);
            _sqliter.open();
            createTable();
        }
        void createTable()
        {
            // create table if not exists binding_table(exchange_name varchar(32), msgqueue_name, binding_key)
            std::stringstream sql;
            sql << "create table if not exists binding_table(";
            sql << "_exchange_name varchar(32), ";
            sql << "_queue_name varchar(32), ";
            sql << "_binding_key varchar(128));";
            assert(_sqliter.exec(sql.str(), nullptr, nullptr));
        }
        void removeTable()
        {
            std::string sql_remove = "drop table if exists binding_table;";
            if (_sqliter.exec(sql_remove, nullptr, nullptr) == false)
            {
                ERR_LOG("删除绑定数据库失败");
                abort(); // 退出程序
            }
        }
        bool insert(const Binding::ptr &binding)
        {
            std::stringstream sql;
            sql << "insert into binding_table values(";
            sql << "'" << binding->_exchange_name << "', ";
            sql << "'" << binding->_queue_name << "', ";
            sql << "'" << binding->_binding_key << "');";
            return _sqliter.exec(sql.str(), nullptr, nullptr);
        }
        // 删除交换机为exchange_name的，队列为queue_name的一个绑定
        void remove(const std::string &exchange_name, const std::string &queue_name)
        {
            std::stringstream sql;
            sql << "delete from binding_table where ";
            sql << "_exchange_name = '" << exchange_name << "' and ";
            sql << "_queue_name = '" << queue_name << "';";
            _sqliter.exec(sql.str(), nullptr, nullptr);
        }
        // 删除删除交换机为exchange_name的所有队列的绑定
        void removeExchangeBindings(const std::string &exchange_name)
        {
            std::stringstream sql;
            sql << "delete from binding_table where ";
            sql << "_exchange_name = '" << exchange_name << "';";
            _sqliter.exec(sql.str(), nullptr, nullptr);
        }
        // 删除某个队列的绑定（可能删除多个)
        void removeQueueBindings(const std::string &queue_name)
        {
            std::stringstream sql;
            sql << "delete from binding_table where ";
            sql << "_queue_name = '" << queue_name << "';";
            _sqliter.exec(sql.str(), nullptr, nullptr);
        }
        BindingMap getAllBinding()
        {
            BindingMap ret;
            std::string sql = "select _exchange_name, _queue_name, _binding_key from binding_table;";
            _sqliter.exec(sql, selectCallback, &ret);
            return ret;
        }

    private:
        static int selectCallback(void *args, int numcol, char **row, char **fields)
        {
            auto binding_map = (BindingMap *)args;
            auto binding = std::make_shared<Binding>();
            binding->_exchange_name = row[0];
            binding->_queue_name = row[1];
            binding->_binding_key = row[2];
            // 这里需要额外实现映射，具体原因看16-20行和35到39行

            // 方式一：从exchange_map中获得一个queue_map，接着再在这个map里面插入绑定数据
            QueueBindingMap &queue_map = (*binding_map)[binding->_exchange_name]; // 使用引用类型，能够保证不存在时自动创建
            queue_map.insert(std::make_pair(binding->_queue_name, binding));

            // 方式二：定义一个临时的queue_map再插入进binding_map
            // QueueBindingMap queue_map;
            // queue_map.insert(std::make_pair(binding->_queue_name, binding));
            // binding_map->insert(std::make_pair(binding->_exchange_name, queue_map));    // 会导致数据覆盖
            return 0;
        }

    private:
        Sqliter _sqliter;
    };
    class BindingManager
    {
    public:
        using ptr = std::shared_ptr<BindingManager>;

        BindingManager(const std::string &data_base_file) : _mapper(data_base_file) 
        {
            _bindings = _mapper.getAllBinding();
        }
        bool bind(const std::string &exchange_name, const std::string &queue_name, const std::string binding_key, bool durable)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(exchange_name);
            // 注意查找绑定，要先查找交换机，再查找队列
            if (it != _bindings.end() && it->second.find(queue_name) != it->second.end())
            {
                return true; // 表示已经存在有绑定了
            }
            Binding::ptr binding = std::make_shared<Binding>(exchange_name, queue_name, binding_key);
            // 实现绑定的持久化存储
            if (durable == true)
            {
                if (_mapper.insert(binding) == false)
                {
                    return false;
                }
            }
            // 定义为引用类型，此时并不存在这个queue_map这个对象，但是map语法会帮我们自动构建
            QueueBindingMap &queue_map = _bindings[exchange_name];
            queue_map.insert(std::make_pair(queue_name, binding));

            return true;
            // 在没有145-151行
            // 绑定信息存进去了吗 是否需要持久化存储 这个需要交换机和队列数据都是持久化，其一不为持久化，绑定信息为持久化无意义
            // 而在该模块中，需要获取交换机数据和队列数据，导致高度耦合！！！
            // 所以回到144行和传入参数的durable，进行外部判断持久化降低耦合！！！
        }
        void unBind(const std::string &exchange_name, const std::string &queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto exchange_it = _bindings.find(exchange_name);
            // 注意查找绑定，要先查找交换机，再查找队列
            if (exchange_it == _bindings.end())
            {
                return;
            }
            auto queue_it = exchange_it->second.find(queue_name);
            if (queue_it == exchange_it->second.end())
            {
                return;
            }
            _mapper.remove(exchange_name, queue_name);
            _bindings[exchange_name].erase(queue_name);
        }
        void removeExchangeBindings(const std::string &exchange_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeExchangeBindings(exchange_name);
            _bindings.erase(exchange_name);
        }
        void removeQueueBindings(const std::string &queue_name)
        {
            // 对绑定信息中的所有交换机中的队列queue_name都删除
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeQueueBindings(queue_name);
            for (auto &e : _bindings)
            {
                e.second.erase(queue_name);
            }
        }
        QueueBindingMap getExchangeBindings(const std::string &exchange_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_bindings.find(exchange_name) == _bindings.end())
            {
                return QueueBindingMap(); // 返回匿名对象
            }
            return _bindings.find(exchange_name)->second;
        }
        Binding::ptr getBinding(const std::string &exchange_name, const std::string &queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto exchange_it = _bindings.find(exchange_name);
            if (exchange_it == _bindings.end()) // 先找交换机映射
            {
                return Binding::ptr();
            }
            auto queue_it = exchange_it->second.find(queue_name); // 再找队列映射
            if (queue_it == exchange_it->second.end())
            {
                return Binding::ptr();
            }
            return queue_it->second; // 最后找到队列映射进行返回
        }
        bool exist(const std::string &exchange_name, const std::string &queue_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto exchange_it = _bindings.find(exchange_name);
            if (exchange_it == _bindings.end()) // 先找交换机映射
            {
                return false;
            }
            auto queue_it = exchange_it->second.find(queue_name); // 再找队列映射
            if (queue_it == exchange_it->second.end())
            {
                return false;
            }
            return true; // 最后找到队列映射进行返回
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _bindings.clear();
        }
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            size_t total_num = 0;
            for (const auto &exchange : _bindings)
            {
                // 一个_bindings存放着若干个交换机，一个交换机存放着若干个queue，一个queue内存放着若干个绑定信息
                // queue = exchange.second
                total_num += exchange.second.size();
            }
            return total_num;
        }

    private:
        std::mutex _mutex;
        BindingMapper _mapper;
        BindingMap _bindings;
    };
};

#endif